home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / database / postgres / postgre4.z / postgre4 / src / lib / libpq / pqpacket.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-08-27  |  7.1 KB  |  281 lines

  1. /*
  2.  * pqpacket.c -- routines for reading and writing data packets
  3.  *    sent/received by POSTGRES clients and servers
  4.  *
  5.  * $Header: /private/postgres/src/lib/libpq/RCS/pqpacket.c,v 1.8 1992/04/21 13:14:18 clarsen Exp $
  6.  *
  7.  * This is the module that understands the lowest-level part
  8.  * of the communication protocol.  All of the trickyness in
  9.  * this module is for making sure that non-blocking IO in
  10.  * the Postmaster works correctly.   Check the notes in PacketRecv
  11.  * on non-blocking I/O.
  12.  *
  13.  * Data Structures:
  14.  *    Port has two important functions. (1) It records the 
  15.  *    sock/addr used in communication. (2) It holds partially
  16.  *    read in messages.  This is especially important when
  17.  *    we haven't seen enough to construct a complete packet 
  18.  *    header.
  19.  *
  20.  * PacketBuf -- None of the clients of this module should know
  21.  *    what goes into a packet hdr (although they know how big
  22.  *    it is).  This routine is in charge of host to net order
  23.  *    conversion for headers.  Data conversion is someone elses
  24.  *    responsibility.
  25.  *
  26.  * Memory Allocation:  is not handled in this module
  27.  *
  28.  * IMPORTANT: these routines are called by backends, clients, and
  29.  *    the Postmaster.
  30.  *
  31.  * NOTE: assume htonl() is sufficient for all header structs.  If
  32.  *    header structs become longs, must switch to htonl().
  33.  */
  34. #include <stdio.h>
  35. #include <sys/types.h>
  36. #include <sys/socket.h>
  37. #include <netdb.h>
  38. #include <netinet/in.h>
  39. #include <fcntl.h>
  40.  
  41. #include "tmp/postgres.h"
  42. #include "utils/log.h"
  43. #include "storage/ipci.h"
  44. #include "tmp/pqcomm.h"
  45.  
  46. extern char PQerrormsg[];
  47.  
  48. /*
  49.  * PacketRecieve -- receive a packet on a port.
  50.  *
  51.  * RETURNS: connection id of the packet sender, if one
  52.  * is available.
  53.  */
  54. PacketReceive(port, buf, nonBlocking, connIdP)
  55. Port        *port;    /* receive port */
  56. PacketBuf    *buf;    /* MAX_PACKET_SIZE-worth of buffer space */
  57. Boolean        nonBlocking; /* NON_BLOCKING or BLOCKING i/o */
  58. ConnId        *connIdP;    /* sender's connection (seqpack) */
  59. {
  60.   int        status;
  61.   PacketLen    cc;            /* character count -- bytes recvd */
  62.   PacketLen    packetLen;     /* remaining packet chars to read */
  63.   Addr    tmp;           /* curr recv buf pointer */
  64.   PacketHdr    *hdr = (PacketHdr *) buf;  /* incoming hdr information */
  65.   int        addrLen = sizeof(struct sockaddr_in);
  66.   int        flag;
  67.   int        decr;
  68.  
  69.   if (nonBlocking) {
  70.     flag = MSG_PEEK;
  71.     decr = 0;
  72.   } else {
  73.     flag = 0;
  74.     decr = sizeof(PacketHdr);
  75.   }
  76.   /*
  77.    * Assume port->nBytes is zero unless we were interrupted during
  78.    * non-blocking I/O.  This first recvfrom() is to get the hdr
  79.    * information so we know how many bytes to read.  Life would
  80.    * be very complicated if we read too much data (buffering).
  81.    */
  82.   tmp = ((Addr)buf) + port->nBytes;
  83.   if (port->nBytes >= sizeof(PacketHdr)) {
  84.     packetLen = htonl(hdr->len) + sizeof(PacketHdr);
  85.   } else {
  86.     cc = recvfrom(port->sock, tmp, sizeof(PacketHdr), flag, 
  87.           &(port->addr), &addrLen);
  88.     if ( cc < sizeof(PacketHdr)) {
  89.       /* if cc is negative, the system call failed */
  90.       if (cc < 0) {
  91.     return(STATUS_ERROR);
  92.       }
  93.       /* 
  94.        * cc == 0 means the connection was broken at the 
  95.        * other end.
  96.        */
  97.       else if (! cc) {
  98.     return(STATUS_INVALID);
  99.  
  100.       } else {
  101.     /*
  102.      * Worst case.  We didn't even read in enough data to
  103.      * get the header.  IN UDP (seq-pack) THIS IS IMPOSSIBLE.
  104.      * Messages are delivered in full packets.  In the stream
  105.      * protocol, it probably won't happen unless the client
  106.      * is malicious (so its even harder to test).
  107.      *
  108.      * Don't save the number of bytes we've read so far.
  109.      * Since we only peeked at the incoming message, the
  110.      * kernel is going to keep it for us.
  111.      */
  112.  
  113.     *connIdP = INVALID_ID;
  114.     return(STATUS_NOT_DONE);
  115.       }
  116.     } else {
  117.  
  118.       /* great. got the header. now get the true length (including
  119.        * header size).
  120.        */
  121.       packetLen = htonl(hdr->len);
  122.       packetLen -= decr;
  123.       tmp += decr - port->nBytes;
  124.     }
  125.   }
  126.  
  127.   /*
  128.    * Now that we know how big it is, read the packet.  We read
  129.    * the entire packet, since the last call was just a peek.
  130.    */
  131.   while (packetLen) { 
  132.     cc = recvfrom(port->sock, tmp, packetLen, NULL, 
  133.           &(port->addr), &addrLen);
  134.     if (cc < 0)
  135.       return(STATUS_ERROR);
  136.  
  137.     /* 
  138.      * cc == 0 means the connection was broken at the 
  139.      * other end.
  140.      */
  141.     else if (! cc) 
  142.       return(STATUS_INVALID);
  143.  
  144.     tmp += cc;
  145.     packetLen -= cc;
  146.  
  147.  
  148.     /* if non-blocking, we're done. */
  149.     if (nonBlocking && packetLen) {
  150.       port->nBytes += cc;
  151.       return(STATUS_NOT_DONE);
  152.     }
  153.   }
  154.  
  155.   *connIdP = htonl(hdr->connId);
  156.   port->nBytes = 0;
  157.   return(STATUS_OK);
  158. }
  159.  
  160.  
  161. /*
  162.  * PacketSend -- send a single-packet message.
  163.  *
  164.  * RETURNS: STATUS_ERROR if the write fails, STATUS_OK otherwise.
  165.  * SIDE_EFFECTS: may block.
  166.  * NOTES: Non-blocking writes would significantly complicate 
  167.  *    buffer management.  For now, we're not going to do it.
  168.  */
  169. PacketSend(port, conn, buf, type, len, nonBlocking)
  170. Port        *port;
  171. Connection    *conn;
  172. PacketBuf    *buf;
  173. MsgType        type;
  174. PacketLen    len;
  175. Boolean        nonBlocking;
  176. {
  177.   int            status;
  178.   PacketLen        totalLen;
  179.   PacketHdr        *hdr = (PacketHdr *) buf;
  180.   int            addrLen = sizeof (struct sockaddr_in);
  181.  
  182.   Assert( ! nonBlocking );
  183.   Assert( buf );
  184.  
  185.   totalLen = len;
  186.  
  187.   hdr->seqno = htonl(conn->seqno++);
  188.   hdr->connId = htonl(conn->id);
  189.   hdr->type = (MsgType)htonl(type);
  190.   hdr->len = htonl(len);
  191.  
  192.   len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
  193.            &(port->addr), addrLen);
  194.  
  195.   if (len < totalLen) {
  196.       strcpy(PQerrormsg,"PacketSend: couldn't send complete packet\n");
  197.     fprintf(stderr,PQerrormsg);
  198.     return(STATUS_ERROR);
  199.   }
  200.  
  201.   return(STATUS_OK);
  202. }
  203.  
  204. /*
  205.  * PacketData -- return components of msg hdr.
  206.  *
  207.  * Clients of this module don't know what the headers look
  208.  * like.  
  209.  *
  210.  * NOTE: seqnoP is an IN/OUT parameter.  The others are out only.
  211.  *
  212.  */
  213. PacketData(buf, dataP, bufSizeP, msgTypeP, seqnoP)
  214. Addr        buf;
  215. Addr     *dataP;
  216. int          *bufSizeP;
  217. MsgType        *msgTypeP;
  218. SeqNo        *seqnoP;
  219. {
  220.   PacketHdr    *hdr = (PacketHdr *) buf;
  221.  
  222.   /* seq pack protocol only */
  223.   if (htonl(hdr->seqno) != *seqnoP)
  224.     *msgTypeP = DUPLICATE_MSG;
  225.   else
  226.     *seqnoP++;
  227.  
  228.   *msgTypeP = (MsgType)htonl(hdr->type);
  229.   *bufSizeP = htonl(hdr->len);
  230.  
  231.   /* data part starts right after the header */
  232.   *dataP = (Addr) (hdr+1);
  233. }
  234.  
  235.  
  236. /*
  237.  * PacketRetransmit -- resend a buffer.  
  238.  *
  239.  * Assume that the header is already initialized.  We're
  240.  * just going to resend the same message.
  241.  */
  242. PacketRetransmit(buf,port,addr)
  243. Addr        buf;
  244. Port        *port;
  245. Addr        addr;
  246. {
  247.   PacketHdr     *hdr = (PacketHdr *) buf;
  248.   PacketLen    len,totalLen;
  249.   int        addrLen = sizeof (struct sockaddr_in);
  250.  
  251.   len = totalLen = htonl(hdr->len);
  252.   len = sendto(port->sock, (Addr) buf, totalLen, /* flags */ 0,
  253.            (struct sockaddr *)addr, addrLen);
  254.  
  255.   if (len < totalLen) {
  256.     strcpy(PQerrormsg,"PacketWrite: couldn't send complete packet\n");
  257.     fprintf(stderr,PQerrormsg);
  258.     return(STATUS_ERROR);
  259.   }
  260.  
  261.   return(STATUS_OK);
  262. }
  263.  
  264.  
  265. /*
  266.  * PacketBuf -- remove the header from a packet buf for
  267.  *     a client.
  268.  *
  269.  * NOTE: not sure this is necessary.  Some clients are going
  270.  *    to have to know how big the thing is in order to do
  271.  *    memory allocation.
  272.  */
  273. PacketBufInit(bufP, bufSizeP)
  274. Addr         *bufP;
  275. PacketLen      *bufSizeP;
  276. {
  277.   *bufP  += sizeof(PacketHdr);
  278.   *bufSizeP -= sizeof(PacketHdr);
  279. }
  280.  
  281.